package org.spring.springboot.app.onlinepay.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.wxpay.sdk.WXPayConstants;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.spring.springboot.app.base.Constants;
import org.spring.springboot.app.base.R;
import org.spring.springboot.app.onlinepay.domain.po.OnlinePayPO;
import org.spring.springboot.app.onlinepay.domain.vo.OnlinePayVO;
import org.spring.springboot.app.onlinepay.service.IOnlinePayService;
import org.spring.springboot.app.sys.systemoption.service.ISystemOptionService;
import org.spring.springboot.component.annotation.AccessTokenVerify;
import org.spring.springboot.util.*;
import org.spring.springboot.util.http.HttpAPIService;
import org.spring.springboot.util.http.HttpResult;
import org.spring.springboot.util.sign.RSA;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;

@Api(description="线上支付操作接口",tags = ApiIndex.OnlinePayController)
@RequestMapping(value = "/api/onlinePay")
@RestController
public class OnlinePayController {
    @Autowired
    private HttpAPIService httpAPIService;
    @Autowired
    private IOnlinePayService onlinePayService;
    @Autowired
    private ISystemOptionService systemOptionService;

    @ApiOperation(value="创建在线支持订单")
    @ApiImplicitParam(name = "token", value = "token", paramType = "query", dataType = "String", required = true)
    @AccessTokenVerify
    @RequestMapping(value = "", method = RequestMethod.POST)
    public R save(@ApiParam(value = "订单对象", required = true) @RequestBody OnlinePayVO vo,BindingResult bindingResult) {
        R result = new R();
        if ( bindingResult.hasErrors() ) {
            result.setCode(1);
            result.setMessage(bindingResult.getAllErrors().get(0).toString());
            result.setMessages(bindingResult.getAllErrors());
            return result;
        }
        OnlinePayPO po = new OnlinePayPO();
        BeanUtils.copyProperties(vo,po);
        int code=onlinePayService.save(po);
        if (code == 0) {
            result.setCode(1);
            result.setMessage("保存失败");
        }
        result.setData(po);
        return result;
    }

    @ApiOperation(value="检查订单状态")
    @ApiImplicitParam(name = "token", value = "token", paramType = "query", dataType = "String", required = true)
    @AccessTokenVerify
    @RequestMapping(value = "/checkPayState", method = RequestMethod.POST)
    public R checkPayState( @ApiParam(value = "线下支付订单ID", required = false) @RequestParam(defaultValue = "")  String id) {
        R result = new R();
        int code=onlinePayService.checkPayState(id);
        if (code == 0) {
            result.setCode(1);
            result.setMessage("订单暂无成功支付！");
        }
        return result;
    }

    @ApiOperation(value="支付宝退款")
    @ApiImplicitParam(name = "token", value = "token", paramType = "query", dataType = "String", required = true)
    @AccessTokenVerify
    @RequestMapping(value = "/alipay/refunAlipay", method = RequestMethod.POST)
    public R refundAlipay(@ApiParam(value = "request", hidden = true) HttpServletRequest request,
                          @ApiParam(value = "response", hidden = true) HttpServletResponse response,
                          @ApiParam(value = "订单支付时传入的商户订单号,不能和 trade_no同时为空。", required = false) @RequestParam(defaultValue = "")  String out_trade_no,
                          @ApiParam(value = "支付宝交易号，和商户订单号不能同时为空", required = false) @RequestParam(defaultValue = "")  String trade_no,
                          @ApiParam(value = "需要退款的金额(该金额不能大于订单金额,单位为元，支持两位小数,如果不穿则需要传入商户订单号退全款)", required = false) @RequestParam(defaultValue = "0")  double refund_amount,
                          @ApiParam(value = "退款的原因说明", required = false) @RequestParam(defaultValue = "")  String refund_reason
    ){
        R result = new R();
        String out_request_no = "";//标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
        if(StringUtils.isNoneBlank(out_trade_no)){
            OnlinePayPO po =onlinePayService.selectByPrimaryKey(out_trade_no);
            if(po==null){
                result.setCode(1);
                result.setMessage("订单不存在!");
                return result;
            }
            if(StringUtils.isBlank(refund_amount+"")){
                refund_amount=po.getMoney();
            }
            if(refund_amount>po.getMoney()){
                result.setCode(1);
                result.setMessage("需要退款的金额，该金额不能大于订单金额!");
                return result;
            }
        }
        Map<String, String> map = new HashMap<String, String>(); //公共请求参数
        map.put("app_id",systemOptionService.getString(Constants.OPTION_ALIPAY_APPID));
        map.put("method",systemOptionService.getString(Constants.OPTION_ALIPAY_TRADE_REFUND));
        map.put("sign_type",systemOptionService.getString(Constants.OPTION_ALIPAY_SIGN_TYPE));
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        map.put("timestamp",  formatter.format(new Date())+"");
        // map.put("charset",  Constants.OPTION_ALIPAY_INPUT_CHARSET);
        map.put("version", systemOptionService.getString(Constants.OPTION_ALIPAY_VERSION));
        Map<String, String> bizmap = new HashMap<String, String>(); //内容参数
        if(StringUtils.isNotBlank(out_trade_no)){
            bizmap.put("out_trade_no",out_trade_no);
        }
        if(StringUtils.isNotBlank(trade_no)){
            bizmap.put("trade_no",trade_no);
        }
        bizmap.put("refund_amount",refund_amount+"");
        bizmap.put("refund_reason",refund_reason);
        ObjectMapper mapper = new ObjectMapper();
        try {
            map.put("biz_content",mapper.writeValueAsString(bizmap));
        } catch (Exception e) {
            // LogFactory.getLog(this.getClass()).error(title, e);
        }
        map.put("sign", RSA.sign(PayUtil.createLinkString(map),systemOptionService.getString(Constants.OPTION_ALIPAY_PRIVATE_KEY),systemOptionService.getString(Constants.OPTION_ALIPAY_INPUT_CHARSET)));
        try{
            String params=mapper.writeValueAsString(map);
            HttpResult resultPost = httpAPIService.doPost("https://openapi.alipay.com/gateway.do",mapper.readValue(params,Map.class));
            Map<String, Object> reMap = mapper.readValue(resultPost.getBody(),Map.class);
            if(reMap.containsKey("alipay_trade_refund_response") && reMap.get("alipay_trade_refund_response") != null){
                reMap = (Map<String, Object>)reMap.get("alipay_trade_refund_response");
            }
            result.setData(reMap);
        } catch (Exception e){
            e.printStackTrace();
            result.setCode(999);
            result.setMessage("下单失败!");
            return result;
        }
        return result;
    }

//    @ApiOperation(value="支付宝转账")
//    @ApiImplicitParam(name = "token", value = "token", paramType = "query", dataType = "String", required = true)
//    @AccessTokenVerify
//    @RequestMapping(value = "/alipay/transferAlipay", method = RequestMethod.POST)
//    public R transferAlipay(@ApiParam(value = "request", hidden = true) HttpServletRequest request,
//                          @ApiParam(value = "response", hidden = true) HttpServletResponse response,
//                          @ApiParam(value = "转账金额", required = false) @RequestParam(defaultValue = "0")  double amount,
//                          @ApiParam(value = "转账账号", required = false) @RequestParam(defaultValue = "")  String emal
//    ){
//        R result = new R();
//
//        Map<String, String> map = new HashMap<String, String>(); //公共请求参数
//        map.put("app_id",systemOptionService.getString(Constants.OPTION_ALIPAY_APPID));
//        map.put("method",systemOptionService.getString(Constants.OPTION_ALIPAY_FUND_TRANS_TOACCOUNT_TRANSFER));
//        map.put("sign_type",systemOptionService.getString(Constants.OPTION_ALIPAY_SIGN_TYPE));
//        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        map.put("timestamp",  formatter.format(new Date())+"");
//        map.put("version", systemOptionService.getString(Constants.OPTION_ALIPAY_VERSION));
//            Map<String, String> bizmap = new HashMap<String, String>(); //内容参数
//
//            bizmap.put("out_biz_no",IdGen.uuid());
//            bizmap.put("payee_type","ALIPAY_LOGONID");
//            bizmap.put("payee_account",emal);
//            bizmap.put("amount",amount+"");
//            bizmap.put("payer_show_name",Constants.OPTION_COMPANY_NAME);
//        ObjectMapper mapper = new ObjectMapper();
//        try {
//            map.put("biz_content",mapper.writeValueAsString(bizmap));
//        } catch (Exception e) {
//            // LogFactory.getLog(this.getClass()).error(title, e);
//        }
//        map.put("sign", RSA.sign(PayUtil.createLinkString(map),systemOptionService.getString(Constants.OPTION_ALIPAY_PRIVATE_KEY),systemOptionService.getString(Constants.OPTION_ALIPAY_INPUT_CHARSET)));
//        try{
//            String params=mapper.writeValueAsString(map);
//            HttpResult resultPost = httpAPIService.doPost("https://openapi.alipay.com/gateway.do",mapper.readValue(params,Map.class));
//            Map<String, Object> reMap = mapper.readValue(resultPost.getBody(),Map.class);
////            if(reMap.containsKey("alipay_trade_refund_response") && reMap.get("alipay_trade_refund_response") != null){
////                reMap = (Map<String, Object>)reMap.get("alipay_trade_refund_response");
////            }
//            result.setData(reMap);
//        } catch (Exception e){
//            e.printStackTrace();
//            result.setCode(999);
//            result.setMessage("下单失败!");
//            return result;
//        }
//        return result;
//    }
    @ApiOperation(value="支付宝支付")
    @ApiImplicitParam(name = "token", value = "token", paramType = "query", dataType = "String", required = true)
    @AccessTokenVerify
    @RequestMapping(value = "/alipay/getPaytTwoDimensionUrl", method = RequestMethod.POST)
    public R alipay(@ApiParam(value = "request", hidden = true) HttpServletRequest request,
                       @ApiParam(value = "response", hidden = true) HttpServletResponse response,
                       @ApiParam(value = "商品描述", required = true) @RequestParam(defaultValue = "")  String body,
                       @ApiParam(value = "订单总金额，单位为元", required = true) @RequestParam(defaultValue = "0")  double total_fee,
                       @ApiParam(value = "终端IP", required = false) @RequestParam(defaultValue = "")  String spbill_create_ip,
                       @ApiParam(value = "订单类型(8.代理商充值)", required = true) @RequestParam(defaultValue = "8")  int type
    ){
        R result = new R();
        OnlinePayPO po = new OnlinePayPO();
        po.setJsondata(onlinePayService.getJsonData(type));
        po.setType(type);
        po.setContent(body);
        po.setMoney( total_fee);
        int code=onlinePayService.save(po);
        if(code<1){
            result.setCode(1);
            result.setMessage("创建在线订单失败!");
            return result;
        }
        Map<String, String> map = new HashMap<String, String>(); //支付参数
        map.put("app_id",systemOptionService.getString(Constants.OPTION_ALIPAY_APPID));
        map.put("method",systemOptionService.getString(Constants.OPTION_ALIPAY_TRADE_PRECREATE));
        map.put("sign_type",systemOptionService.getString(Constants.OPTION_ALIPAY_SIGN_TYPE));
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        map.put("timestamp",  formatter.format(po.getCreateDate())+"");
        map.put("notify_url",systemOptionService.getString(Constants.OPTION_ALIPAY_NOTIFY_URL));
        map.put("version", systemOptionService.getString(Constants.OPTION_ALIPAY_VERSION));
            Map<String, String> bizmap = new HashMap<String, String>(); //内容参数
            bizmap.put("out_trade_no",po.getId());
            bizmap.put("seller_id",systemOptionService.getString(Constants.OPTION_ALIPAY_SELLER_ID));
            bizmap.put("total_amount",total_fee+"");
            bizmap.put("subject",body);
            bizmap.put("body",body);
            bizmap.put("timeout_express","1c");
        ObjectMapper mapper = new ObjectMapper();
        try {
            map.put("biz_content",mapper.writeValueAsString(bizmap));
        } catch (Exception e) {
           // LogFactory.getLog(this.getClass()).error(title, e);
        }
        map.put("sign", RSA.sign(PayUtil.createLinkString(map),systemOptionService.getString(Constants.OPTION_ALIPAY_PRIVATE_KEY),systemOptionService.getString(Constants.OPTION_ALIPAY_INPUT_CHARSET)));
        try{
            String params=mapper.writeValueAsString(map);
            HttpResult resultPost = httpAPIService.doPost("https://openapi.alipay.com/gateway.do",mapper.readValue(params,Map.class));
            Map<String, Object> reMap = mapper.readValue(resultPost.getBody(),Map.class);
            if(reMap.containsKey("alipay_trade_precreate_response") && reMap.get("alipay_trade_precreate_response") != null){
                 reMap = (Map<String, Object>)reMap.get("alipay_trade_precreate_response");
            }
            result.setData(reMap);
        } catch (Exception e){
            e.printStackTrace();
            result.setCode(999);
            result.setMessage("下单失败!");
            return result;
        }
        return result;
    }

    @ApiOperation(value="支付宝异步回调")
    @RequestMapping(value = "/alipay_notify", method = RequestMethod.POST)
    public void alipay_notify(HttpServletRequest request, HttpServletResponse response) {
        String title ="alipay";
        String systemSellerId1 = systemOptionService.getString(Constants.OPTION_ALIPAY_SELLER_ID);
        List<String> validatelist = new ArrayList<String>();//需要校验的商户集合
       validatelist.add(systemSellerId1.toLowerCase());
        String successState =systemOptionService.getString(Constants.OPTION_ALIPAY_PAY_SUCCESS_STATE);
        onlinePayService.doAlipay(request,response,validatelist,successState,title);
    }



    @ApiOperation(value="获取微信支付二维码URl")
    @ApiImplicitParam(name = "token", value = "token", paramType = "query", dataType = "String", required = true)
    @AccessTokenVerify
    @RequestMapping(value = "/wxpay/getPaytTwoDimensionUrl", method = RequestMethod.POST)
    public R wxpay( @ApiParam(value = "request", hidden = true) HttpServletRequest request,
                         @ApiParam(value = "response", hidden = true) HttpServletResponse response,
                         @ApiParam(value = "商品描述", required = true) @RequestParam(defaultValue = "")  String body,
                         @ApiParam(value = "订单总金额，单位为分", required = true) @RequestParam(defaultValue = "0")  double total_fee,
                         @ApiParam(value = "终端IP", required = false) @RequestParam(defaultValue = "")  String spbill_create_ip,
                         @ApiParam(value = "订单类型(8.代理商后台充值)", required = true) @RequestParam(defaultValue = "8")  int type
    ) {
        R result = new R();
        OnlinePayPO po = new OnlinePayPO();
        po.setJsondata("");
        po.setType(type);
        po.setContent(body);
        po.setMoney(total_fee);
        int code=onlinePayService.save(po);
        if(code<1){
            result.setCode(1);
            result.setMessage("创建在线订单失败!");
            return result;
        }
        int total_fees=(int) Arith.mul(NumberUtil.parseDouble(total_fee),100.00);
        Map<String, String> map = new HashMap<String, String>();
        map.put("appid",systemOptionService.getString(Constants.OPTION_WXPAY_APPID));
        map.put("mch_id",systemOptionService.getString(Constants.OPTION_WXPAY_MCHID));
        map.put("nonce_str", WXPayUtil.generateNonceStr());
        map.put("body", body);
        map.put("out_trade_no",  po.getId());
        map.put("total_fee", total_fees+"");
        map.put("spbill_create_ip", StringUtils.isBlank(spbill_create_ip) ? IpUtil.getIpAddr(request):spbill_create_ip);
        map.put("notify_url", systemOptionService.getString(Constants.OPTION_WX_CREATE_ORDER_URL));
        map.put("trade_type", systemOptionService.getString(Constants.OPTION_WXPAY_TRADE_TYPE));
        map.put("product_id",  po.getId());
        String xml = "";
        try{
           // Map<String, Object> newmap = new HashMap<String, Object>();
           // newmap.put(WXPayConstants.FIELD_SIGN,WXPayUtil.generateSignature(map,systemOptionService.getString(Constants.OPTION_WXPAY_KEY)));
            xml = WXPayUtil.generateSignedXml(map,systemOptionService.getString(Constants.OPTION_WXPAY_KEY));
            String resultPost = httpAPIService.post(WXPayConstants.UNIFIEDORDER_URL,xml);
            Map<String, String> resultMap = WXPayUtil.xmlToMap(resultPost);
            if(resultMap.containsKey("return_code") && WXPayConstants.SUCCESS.equals(resultMap.get("return_code").toString())
                    &&resultMap.containsKey("result_code") && WXPayConstants.SUCCESS.equals(resultMap.get("result_code").toString())){
                map = new HashMap<String, String>();
                map.put("code_url",resultMap.get("code_url"));
                map.put("prepay_id",resultMap.get("prepay_id"));
                map.put("trade_type",resultMap.get("trade_type"));
                map.put("out_trade_no", po.getId());
                result.setData(map);
            }else{
                result.setData(resultMap);
                result.setCode(1);
                result.setMessage("下单失败!");
            }
           // result.setData(resultPost);
        } catch (Exception e){
            e.printStackTrace();
            result.setCode(999);
            result.setMessage("下单失败!");
            return result;
        }
        return result;
    }

    @ApiOperation(value="微信异步回调")
    @RequestMapping(value = "/wxpay_notify", method = RequestMethod.POST)
    public void wxpay_notify(HttpServletRequest request, HttpServletResponse response) {
        String title = "weixin";
        String systemAppId1  =systemOptionService.getString(Constants.OPTION_WXPAY_APPID);
        String systemMchId1 = systemOptionService.getString(Constants.OPTION_WXPAY_MCHID);
        List<String> validatelist = new ArrayList<String>();//需要校验的商户集合
        validatelist.add((systemAppId1+systemMchId1).toLowerCase());
        String successState = systemOptionService.getString(Constants.OPTION_API_WEIXIN_PAY_SUCCESS_STATE);
        onlinePayService.doWeiXin(request,response,validatelist,successState,title);
    }
}
